/*
 * Copyright 2019-2020 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_display.h"
#include "fsl_rm68200.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define RM68200_DelayMs VIDEO_DelayMs

/*******************************************************************************
 * Variables
 ******************************************************************************/
static const uint8_t lcmInitSetting[][2] = {
    {0xFE, 0x01},
    {0x24, 0xC0},
    {0x25, 0x53},
    {0x26, 0x00},
    {0x2B, 0xE5},
    {0x27, 0x0A},
    {0x29, 0x0A},
    {0x16, 0x52},
    {0x2F, 0x53},
    {0x34, 0x5A},
    {0x1B, 0x00},
    {0x12, 0x0A},
    {0x1A, 0x06},
    {0x46, 0x56},
    {0x52, 0xA0},
    {0x53, 0x00},
    {0x54, 0xA0},
    {0x55, 0x00},
    /* 2 data lanes */
    {0x5F, 0x11},

    {0xFE, 0x03},
    {0x00, 0x05},
    {0x02, 0x0B},
    {0x03, 0x0F},
    {0x04, 0x7D},
    {0x05, 0x00},
    {0x06, 0x50},
    {0x07, 0x05},
    {0x08, 0x16},
    {0x09, 0x0D},
    {0x0A, 0x11},
    {0x0B, 0x7D},
    {0x0C, 0x00},
    {0x0D, 0x50},
    {0x0E, 0x07},
    {0x0F, 0x08},
    {0x10, 0x01},
    {0x11, 0x02},
    {0x12, 0x00},
    {0x13, 0x7D},
    {0x14, 0x00},
    {0x15, 0x85},
    {0x16, 0x08},
    {0x17, 0x03},
    {0x18, 0x04},
    {0x19, 0x05},
    {0x1A, 0x06},
    {0x1B, 0x00},
    {0x1C, 0x7D},
    {0x1D, 0x00},
    {0x1E, 0x85},
    {0x1F, 0x08},
    {0x20, 0x00},
    {0x21, 0x00},
    {0x22, 0x00},
    {0x23, 0x00},
    {0x24, 0x00},
    {0x25, 0x00},
    {0x26, 0x00},
    {0x27, 0x00},
    {0x28, 0x00},
    {0x29, 0x00},
    {0x2A, 0x07},
    {0x2B, 0x08},
    {0x2D, 0x01},
    {0x2F, 0x02},
    {0x30, 0x00},
    {0x31, 0x40},
    {0x32, 0x05},
    {0x33, 0x08},
    {0x34, 0x54},
    {0x35, 0x7D},
    {0x36, 0x00},
    {0x37, 0x03},
    {0x38, 0x04},
    {0x39, 0x05},
    {0x3A, 0x06},
    {0x3B, 0x00},
    {0x3D, 0x40},
    {0x3F, 0x05},
    {0x40, 0x08},
    {0x41, 0x54},
    {0x42, 0x7D},
    {0x43, 0x00},
    {0x44, 0x00},
    {0x45, 0x00},
    {0x46, 0x00},
    {0x47, 0x00},
    {0x48, 0x00},
    {0x49, 0x00},
    {0x4A, 0x00},
    {0x4B, 0x00},
    {0x4C, 0x00},
    {0x4D, 0x00},
    {0x4E, 0x00},
    {0x4F, 0x00},
    {0x50, 0x00},
    {0x51, 0x00},
    {0x52, 0x00},
    {0x53, 0x00},
    {0x54, 0x00},
    {0x55, 0x00},
    {0x56, 0x00},
    {0x58, 0x00},
    {0x59, 0x00},
    {0x5A, 0x00},
    {0x5B, 0x00},
    {0x5C, 0x00},
    {0x5D, 0x00},
    {0x5E, 0x00},
    {0x5F, 0x00},
    {0x60, 0x00},
    {0x61, 0x00},
    {0x62, 0x00},
    {0x63, 0x00},
    {0x64, 0x00},
    {0x65, 0x00},
    {0x66, 0x00},
    {0x67, 0x00},
    {0x68, 0x00},
    {0x69, 0x00},
    {0x6A, 0x00},
    {0x6B, 0x00},
    {0x6C, 0x00},
    {0x6D, 0x00},
    {0x6E, 0x00},
    {0x6F, 0x00},
    {0x70, 0x00},
    {0x71, 0x00},
    {0x72, 0x20},
    {0x73, 0x00},
    {0x74, 0x08},
    {0x75, 0x08},
    {0x76, 0x08},
    {0x77, 0x08},
    {0x78, 0x08},
    {0x79, 0x08},
    {0x7A, 0x00},
    {0x7B, 0x00},
    {0x7C, 0x00},
    {0x7D, 0x00},
    {0x7E, 0xBF},
    {0x7F, 0x02},
    {0x80, 0x06},
    {0x81, 0x14},
    {0x82, 0x10},
    {0x83, 0x16},
    {0x84, 0x12},
    {0x85, 0x08},
    {0x86, 0x3F},
    {0x87, 0x3F},
    {0x88, 0x3F},
    {0x89, 0x3F},
    {0x8A, 0x3F},
    {0x8B, 0x0C},
    {0x8C, 0x0A},
    {0x8D, 0x0E},
    {0x8E, 0x3F},
    {0x8F, 0x3F},
    {0x90, 0x00},
    {0x91, 0x04},
    {0x92, 0x3F},
    {0x93, 0x3F},
    {0x94, 0x3F},
    {0x95, 0x3F},
    {0x96, 0x05},
    {0x97, 0x01},
    {0x98, 0x3F},
    {0x99, 0x3F},
    {0x9A, 0x0F},
    {0x9B, 0x0B},
    {0x9C, 0x0D},
    {0x9D, 0x3F},
    {0x9E, 0x3F},
    {0x9F, 0x3F},
    {0xA0, 0x3F},
    {0xA2, 0x3F},
    {0xA3, 0x09},
    {0xA4, 0x13},
    {0xA5, 0x17},
    {0xA6, 0x11},
    {0xA7, 0x15},
    {0xA9, 0x07},
    {0xAA, 0x03},
    {0xAB, 0x3F},
    {0xAC, 0x3F},
    {0xAD, 0x05},
    {0xAE, 0x01},
    {0xAF, 0x17},
    {0xB0, 0x13},
    {0xB1, 0x15},
    {0xB2, 0x11},
    {0xB3, 0x0F},
    {0xB4, 0x3F},
    {0xB5, 0x3F},
    {0xB6, 0x3F},
    {0xB7, 0x3F},
    {0xB8, 0x3F},
    {0xB9, 0x0B},
    {0xBA, 0x0D},
    {0xBB, 0x09},
    {0xBC, 0x3F},
    {0xBD, 0x3F},
    {0xBE, 0x07},
    {0xBF, 0x03},
    {0xC0, 0x3F},
    {0xC1, 0x3F},
    {0xC2, 0x3F},
    {0xC3, 0x3F},
    {0xC4, 0x02},
    {0xC5, 0x06},
    {0xC6, 0x3F},
    {0xC7, 0x3F},
    {0xC8, 0x08},
    {0xC9, 0x0C},
    {0xCA, 0x0A},
    {0xCB, 0x3F},
    {0xCC, 0x3F},
    {0xCD, 0x3F},
    {0xCE, 0x3F},
    {0xCF, 0x3F},
    {0xD0, 0x0E},
    {0xD1, 0x10},
    {0xD2, 0x14},
    {0xD3, 0x12},
    {0xD4, 0x16},
    {0xD5, 0x00},
    {0xD6, 0x04},
    {0xD7, 0x3F},
    {0xDC, 0x02},
    {0xDE, 0x12},
    {0xFE, 0x0E},
    {0x01, 0x75},

    /* Gamma Settings */
    {0xFE, 0x04},
    {0x60, 0x00},
    {0x61, 0x0C},
    {0x62, 0x12},
    {0x63, 0x0E},
    {0x64, 0x06},
    {0x65, 0x12},
    {0x66, 0x0E},
    {0x67, 0x0B},
    {0x68, 0x15},
    {0x69, 0x0B},
    {0x6A, 0x10},
    {0x6B, 0x07},
    {0x6C, 0x0F},
    {0x6D, 0x12},
    {0x6E, 0x0C},
    {0x6F, 0x00},
    {0x70, 0x00},
    {0x71, 0x0C},
    {0x72, 0x12},
    {0x73, 0x0E},
    {0x74, 0x06},
    {0x75, 0x12},
    {0x76, 0x0E},
    {0x77, 0x0B},
    {0x78, 0x15},
    {0x79, 0x0B},
    {0x7A, 0x10},
    {0x7B, 0x07},
    {0x7C, 0x0F},
    {0x7D, 0x12},
    {0x7E, 0x0C},
    {0x7F, 0x00},

    /* Page 0. */
    {0xFE, 0x00},
    {0x11, 0x00},
};

const display_operations_t rm68200_ops = {
    .init   = RM68200_Init,
    .deinit = RM68200_Deinit,
    .start  = RM68200_Start,
    .stop   = RM68200_Stop,
};

/*******************************************************************************
 * Code
 ******************************************************************************/

status_t RM68200_Init(display_handle_t *handle, const display_config_t *config)
{
    uint32_t i;
    uint8_t param[2];
    status_t status                    = kStatus_Success;
    const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource);
    mipi_dsi_device_t *dsiDevice       = resource->dsiDevice;

    /* Only support 720 * 1280 */
    if (config->resolution != FSL_VIDEO_RESOLUTION(720, 1280))
    {
        return kStatus_InvalidArgument;
    }

    /* Power on. */
    resource->pullPowerPin(true);
    RM68200_DelayMs(1);

    /* Perform reset. */
    resource->pullResetPin(false);
    RM68200_DelayMs(1);
    resource->pullResetPin(true);
    RM68200_DelayMs(5);

    /* Set the LCM init settings. */
    for (i = 0; i < ARRAY_SIZE(lcmInitSetting); i++)
    {
        status = MIPI_DSI_GenericWrite(dsiDevice, lcmInitSetting[i], 2);

        if (kStatus_Success != status)
        {
            return status;
        }
    }

    RM68200_DelayMs(200);

    param[0] = 0x29;
    param[1] = 0x00;
    status   = MIPI_DSI_GenericWrite(dsiDevice, param, 2);
    if (kStatus_Success != status)
    {
        return status;
    }

    RM68200_DelayMs(100);

    param[0] = 0x2c;
    status   = MIPI_DSI_GenericWrite(dsiDevice, param, 1);
    if (kStatus_Success != status)
    {
        return status;
    }

    param[0] = 0x35;
    param[1] = 0x00;
    status   = MIPI_DSI_GenericWrite(dsiDevice, param, 2);
    if (kStatus_Success != status)
    {
        return status;
    }

    RM68200_DelayMs(200);

    return kStatus_Success;
}

status_t RM68200_Deinit(display_handle_t *handle)
{
    const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource);
    mipi_dsi_device_t *dsiDevice       = resource->dsiDevice;

    (void)MIPI_DSI_DCS_EnterSleepMode(dsiDevice, true);

    resource->pullResetPin(false);
    resource->pullPowerPin(false);

    return kStatus_Success;
}

status_t RM68200_Start(display_handle_t *handle)
{
    const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource);
    mipi_dsi_device_t *dsiDevice       = resource->dsiDevice;

    return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, true);
}

status_t RM68200_Stop(display_handle_t *handle)
{
    const rm68200_resource_t *resource = (const rm68200_resource_t *)(handle->resource);
    mipi_dsi_device_t *dsiDevice       = resource->dsiDevice;

    return MIPI_DSI_DCS_SetDisplayOn(dsiDevice, false);
}
